/*
 * SimpleStipulation.java
 *
 * Created on August 4, 2005, 8:44 PM
 *
 */
package com.xucia.jsponic.data;

import java.util.Map;
import java.util.TreeMap;

import com.xucia.jsponic.util.StringEncoder;

/**
 *
 * @author kris.zyp
 */
public class SimpleStipulation implements Stipulation {
    public static final int EQUALS = 0;
    public static final int NOT_EQUALS = 1;
    public static final int LESS_THAN = 2;
    public static final int GREATER_THAN = 3;
    public static final int STARTS_WITH = 4;
    public static Stipulation createStipulation(String str) {
        String[] strings;
        strings = str.split("!=");
        if (strings.length > 1) {
            SimpleStipulation stipulation = new SimpleStipulation();
            stipulation.name = strings[0];
            String value = strings[1].trim();
            if (!(value.startsWith("'") && value.endsWith("'")))
        		throw new RuntimeException("Unable to parse the string value " + value);            
            stipulation.value = value.substring(1,value.length()-1).replaceAll("''","'");
            stipulation.comparison = NOT_EQUALS;
            return stipulation;
        }
        strings = str.split("=");
        if (strings.length > 1) {
            SimpleStipulation stipulation = new SimpleStipulation();
            stipulation.name = strings[0];
            String value = strings[1].trim();
            if (!(value.startsWith("'") && value.endsWith("'")))
        		throw new RuntimeException("Unable to parse the string value " + value);            
            stipulation.value = value.substring(1,value.length()-1).replaceAll("''","'");
            stipulation.comparison = EQUALS;
            return stipulation;
        }
        strings = str.split("<");
        if (strings.length > 1) {
            SimpleStipulation stipulation = new SimpleStipulation();
            stipulation.name = strings[0];
            stipulation.value = strings[1];
            stipulation.comparison = LESS_THAN;
            return stipulation;
        }
        strings = str.split(">");
        if (strings.length > 1) {
            SimpleStipulation stipulation = new SimpleStipulation();
            stipulation.name = strings[0];
            stipulation.value = strings[1];
            stipulation.comparison = GREATER_THAN;
            return stipulation;
        }
        throw new RuntimeException("Unable to parse " + str + " into a simple stipulation");
    }

    /** Creates a new instance of SimpleStipulation */
    public SimpleStipulation() {
    }

    public SimpleStipulation(String name, Object value) {
        this.name = name;
        this.value = value;
    }
    String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    Object value;
    public Object getValue() {
        return value;
    }
    public void setValue(Object value) {
        this.value = value;
    }
    int comparison = 0;
    public int getComparison() {
        return comparison;
    }
    public void setValue(int comparison) {
        this.comparison = comparison;
    }

    public boolean qualifies(Object obj) {
        if (obj instanceof Persistable) {
            Object value = ((Persistable) obj).get(getName());
            //System.err.println("qualifies " + value + " = " + getValue() + " " + (value == getValue()));
            if (comparison == EQUALS) {
	            if (value == null) {
	                if (getValue() == null)
	                    return true;
	            }
	            else {
	                if (value.equals(getValue())) {
	                    return true;
	                }
	            }
	            return false;
            }
            if (comparison == NOT_EQUALS) {
	            if (value == null) {
	                if (getValue() == null)
	                    return false;
	            }
	            else {
	                if (value.equals(getValue())) {
	                    return false;
	                }
	            }
	            return true;
            }
        }
        return false;
    }
    private static StringEncoder sqlStringEncoder = new StringEncoder();
    static {
    	sqlStringEncoder.setUnsafeStrings(new String[] {"'"}, new String[] {"''"});
    }

    private String getValueString(Object value) { 
		if (value instanceof String)
			return "'"+ sqlStringEncoder.encode((String) value) + "'";
		else if (value instanceof Persistable) 
			return "{id:\""+ ((Persistable) value).getId() + "\"}";
		else if (value instanceof Number)
			return value.toString();
		else
			throw new RuntimeException("Can not serialize value in stipulation " + value);    	
    }
    @Override
	public String toString() {
    	String valueString = getValueString(value);
        if (comparison == EQUALS)
            return name + "=" + valueString;
        if (comparison == NOT_EQUALS)
            return name + "!=" + valueString;
        if (comparison == LESS_THAN)
            return name + "<" + valueString;
        if (comparison == GREATER_THAN)
            return name + ">" + valueString;
        throw new RuntimeException("unknown comparison operator");
    }

    public Map getNameValueMap() {
        System.err.println(" adding value " + value);
        Map nameValueMap = new TreeMap();
        nameValueMap.put(name,value);
        return nameValueMap;
    }

    public void addToNameValueMap(Map map) {
        map.put(name,value);
    }

    @Override
	public SimpleStipulation clone() {
        try {
            return (SimpleStipulation) super.clone();
        }
        catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof SimpleStipulation) {
 			return (((SimpleStipulation)obj).name.equals(name) && 
					((SimpleStipulation)obj).value.equals(value) &&
					((SimpleStipulation)obj).comparison==comparison);				
		}
		return false;
	}

	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		if (value == null)
			return name.hashCode() + comparison;
		return name.hashCode() + value.hashCode() + comparison;
	}
	
    
}
